package ferp.core.game;

import ferp.core.util.Convert;

import java.text.NumberFormat;

/**
* User: igorgok
* Date: 5/28/12 5:32 PM
*/
public class Statistics
{
  public static final NumberFormat nf = NumberFormat.getNumberInstance();

  // number of games played so far
  public long numOfGames;
  // total played pool
  public long totalPool;
  // total score
  public long totalAmount;

  // game's statistics
  public static class Games
  {
    // number of games played so far
    public long played;
    // total score for rating
    public long pool;
    // number of deleted games
    public long deleted;

    private void add(Games other)
    {
      played  += other.played;
      pool    += other.pool;
      deleted += other.deleted;
    }
  }

  public static class Sets
  {
    // total number of deals
    public long deals;
    // total number of passing sets
    public long passing;

    private void add(Sets other)
    {
      deals += other.deals;
      passing += other.passing;
    }
  }

  // aggregation data
  public static class Aggregation
  {
    public long sets;
    public long tricks;
    public long success;

    private void add(Aggregation other)
    {
      sets += other.sets;
      tricks += other.tricks;
      success += other.success;
    }
  }

  // percentage statistics
  public static class Percentage
  {
    public long total;
    public int pos; // percentage of success

    public Percentage(long success, long total)
    {
      this.total = total;

      pos = total == 0 ? 0 : (int)(100 * success / total);
    }

    public String pos() {return pos + "%";}
  }

  // ratio statistics
  public static class Ratio
  {
    public long x;
    public long y;

    public Ratio(long x, long y)
    {
      this.x = x;
      this.y = y;
    }

    @Override
    public String toString()
    {
      if (x == 0 || y == 0)
        return x + "/" + y;

      return nf.format((double)x / (double)y);
    }
  }

  // game statistics
  public Games games = new Games();
  // set statistics
  public Sets sets = new Sets();
  // player's score
  public long[] score = new long[Game.PLAYERS];
  // number of times player declared "without3"
  public long[] without3 = new long[Game.PLAYERS];
  // number of times player declared "pass" in contracting
  public long[] passes = new long[Game.PLAYERS];
  // number of passing tricks
  public long[] passingTricks = new long[Game.PLAYERS];
  // tricking sets aggregation (per bid)
  private Aggregation[][] tricking = new Aggregation[Game.PLAYERS][5];
  // misere sets aggregation
  public Aggregation[] misere = new Aggregation[Game.PLAYERS];
  // whists sets aggregation
  public Aggregation[] whists = new Aggregation[Game.PLAYERS];

  public Statistics()
  {
    for (int i = 0; i < Game.PLAYERS; ++i)
    {
      for (int j = 0; j < tricking[i].length; ++j)
        tricking[i][j] = new Aggregation();

      misere[i] = new Aggregation();
      whists[i] = new Aggregation();
    }
  }

  public void update50()
  {
    if (tricking[0].length == 11)
      for (int i = 0; i < Game.PLAYERS; ++i)
      {
        Aggregation[] row = new Aggregation[5];

        System.arraycopy(tricking[i], 6, row, 0, row.length);
        tricking[i] = row;
      }
  }

  public final void update(Statistics other)
  {
    // old statistics
    numOfGames++;

    totalPool   += other.totalPool;
    totalAmount += other.score[0];

    // new statistics
    games.pool += other.totalPool;
    games.played++;

    games.add(other.games);
    sets.add(other.sets);

    for (int i = 0; i < Game.PLAYERS; ++i)
    {
      score[i] += other.score[i];
      without3[i] += other.without3[i];
      passes[i] += other.passes[i];
      passingTricks[i] += other.passingTricks[i];

      for (int j = 0; j < tricking[i].length; ++j)
        tricking[i][j].add(other.tricking[i][j]);

      misere[i].add(other.misere[i]);
      whists[i].add(other.whists[i]);
    }
  }

  public void updateTricking(int id, int contract, int tricks)
  {
    Aggregation a = tricking[id][Convert.index(contract)];

    a.tricks += tricks;
    a.sets++;

    if (tricks >= contract)
      a.success++;
  }

  public long[] getAverageScore()
  {
    long[] result = new long[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
      result[i] = games.played == 0 ? 0 : score[i] / games.played;

    return result;
  }

  public long getNumberOfTrickingSets()
  {
    int n = 0;

    for (int i = 0; i < Game.PLAYERS; ++i)
      for (int j = 0; j < tricking[i].length; ++j)
        n += tricking[i][j].sets;

    return n;
  }

  public Percentage[] getTrickingSetResult(int contract)
  {
    Percentage[] result = new Percentage[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
    {
      Aggregation a = tricking[i][Convert.index(contract)];

      result[i] = new Percentage(a.success, a.sets);
    }

    return result;
  }

  public Percentage[] getMisereSetResult()
  {
    Percentage[] result = new Percentage[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
      result[i] = new Percentage(misere[i].success, misere[i].sets);

    return result;
  }

  public double[] getAveragePassingTricks()
  {
    double[] result = new double[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
      result[i] = sets.passing == 0 ? 0 : (double)passingTricks[i] / (double)sets.passing;

    return result;
  }

  public Percentage[] getWhistedSets()
  {
    Percentage[] result = new Percentage[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
      result[i] = new Percentage(whists[i].success, whists[i].sets);

    return result;
  }

  public Ratio[] getRatioWhistsToPasses()
  {
    Ratio[] result = new Ratio[Game.PLAYERS];

    for (int i = 0; i < Game.PLAYERS; ++i)
      result[i] = new Ratio(whists[i].sets, passes[i]);

    return result;
  }

  @Override
  public String toString() {return "games: " + numOfGames + ", pool: " + totalPool + ", score: " + totalAmount;}

  public static void main(String[] argv)
  {
    System.out.println(nf.format((double)20 / (double)8));
  }

  static
  {
    nf.setMinimumFractionDigits(2);
    nf.setMaximumFractionDigits(2);
  }
}
